Skip to content

Conversation

zombieJ
Copy link
Member

@zombieJ zombieJ commented Jun 24, 2025

在 Form 组件中注册一个 useLayoutEffect 用于跟随 React 生命周期保证时序。没问题的话就继续修。

close #755

Summary by CodeRabbit

  • 新功能

    • 表单组件新增批量更新机制,提升大数据量场景下的性能,减少不必要的重复渲染。
    • 新增批量更新相关的内部方法与组件,支持批量执行回调任务。
    • 新增调试相关的文档和示例,展示如何在复杂表单中进行高效调试。
  • 文档

    • 增加了调试功能的使用说明及代码示例,便于用户参考和学习。

Copy link

vercel bot commented Jun 24, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
field-form ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 27, 2025 3:49am

Copy link

coderabbitai bot commented Jun 24, 2025

Walkthrough

此次更改引入了表单批量更新机制,涵盖了核心表单组件、上下文、类型定义以及相关的 React 组件。新增了批量更新组件 BatchUpdate,并在表单内部通过上下文和 hooks 实现批量 watcher 通知。文档部分新增了 debug 示例及其演示说明。

Changes

文件/路径分组 变更摘要
docs/demo/debug.md 新增 debug 文档,嵌入 debug 示例代码片段。
docs/examples/debug.tsx 新增 React 示例,展示大数据量表单与 watcher 的性能表现。
src/BatchUpdate.tsx 新增批量更新组件,支持按 key 批量执行回调并通过 ref 暴露 batch 方法。
src/FieldContext.ts Context 默认值的内部 hooks 新增 setBatchUpdate 方法。
src/Form.tsx 表单组件新增批量更新逻辑,集成 BatchUpdate 组件和 setBatchUpdate。
src/interface.ts InternalHooks 接口新增 setBatchUpdate 方法签名及 BatchTask 类型导入。
src/useForm.ts FormStore 新增批量 watcher 通知与 batchUpdate 机制,相关方法实现。

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant Form
    participant BatchUpdate
    participant FormStore
    participant Watcher

    App->>Form: 渲染表单
    Form->>BatchUpdate: 挂载并获取 ref
    Form->>FormStore: setBatchUpdate(batchUpdate)
    FormStore->>Form: 注册 setBatchUpdate

    Note over FormStore: 注册/注销 Field 时
    FormStore->>FormStore: batchNotifyWatch(namePath)
    FormStore->>BatchUpdate: batch(key, callback)
    BatchUpdate->>FormStore: 批量执行 callback
    FormStore->>Watcher: notifyWatch(namePath)
Loading

Poem

🐇
新批量机制悄然生,
表单高效更从容。
Watcher 通知不再乱,
批次更新巧调控。
Debug 示例添新意,
代码世界乐无穷!

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

docs/examples/debug.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/.eslintrc.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

src/FieldContext.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/.eslintrc.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

src/useForm.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/.eslintrc.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

  • 3 others
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch fix-batch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@zombieJ zombieJ changed the title fix: batch remove laggy [WIP] fix: batch remove laggy Jun 24, 2025
@crazyair
Copy link
Contributor

看了下,还是很卡啊

@zombieJ
Copy link
Member Author

zombieJ commented Jun 25, 2025

看了下,还是很卡啊

只做了 unmount,没问题再切 mount

@crazyair
Copy link
Contributor

看了下,还是很卡啊

只做了 unmount,没问题再切 mount

试了,目前来看没问题,但是 getFieldsValue() 为啥会 setValue,耗费性能

@zombieJ
Copy link
Member Author

zombieJ commented Jun 25, 2025

试了,目前来看没问题,但是 getFieldsValue() 为啥会 setValue,耗费性能

因为 getFieldsValue 会递归创建一个 Store 镜像,v6 里其实可以直接用 Proxy 搞一个了。

Copy link

codecov bot commented Jun 25, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.45%. Comparing base (6611c31) to head (74cba3e).
Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #757      +/-   ##
==========================================
+ Coverage   99.44%   99.45%   +0.01%     
==========================================
  Files          18       19       +1     
  Lines        1260     1296      +36     
  Branches      298      315      +17     
==========================================
+ Hits         1253     1289      +36     
  Misses          7        7              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@zombieJ zombieJ changed the title [WIP] fix: batch remove laggy fix: batch remove laggy Jun 27, 2025
@zombieJ zombieJ marked this pull request as ready for review June 27, 2025 07:39
@zombieJ zombieJ merged commit 4b12dd0 into master Jun 27, 2025
11 of 12 checks passed
@zombieJ zombieJ deleted the fix-batch branch June 27, 2025 07:42
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/BatchUpdate.tsx (1)

9-32: 批处理实现逻辑正确,但需考虑复杂性

实现逻辑合理:

  • 使用useState收集批处理任务
  • 通过useLayoutEffect确保正确的执行时序
  • 使用useImperativeHandle暴露batch方法

从之前的评论来看,开发者考虑过更简单的方案如防抖或Promise.resolve。当前方案的优势是保持React的时序控制,但确实增加了复杂性。

src/useForm.ts (1)

668-668: 正确替换为批量通知调用。

notifyWatch 调用替换为 batchNotifyWatch 调用是正确的优化:

  • 第668行:在字段注册时使用批量通知
  • 第708行:在字段注销时使用批量通知

这样可以避免在字段注册/注销过程中的频繁通知,符合性能优化的目标。

Also applies to: 708-708

🧹 Nitpick comments (1)
src/BatchUpdate.tsx (1)

24-27: 扩展运算符性能考虑

在批处理任务较多时,频繁使用扩展运算符...ori可能会影响性能。如果批处理键值对数量很大,可以考虑使用其他方式更新状态。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6611c31 and 74cba3e.

📒 Files selected for processing (7)
  • docs/demo/debug.md (1 hunks)
  • docs/examples/debug.tsx (1 hunks)
  • src/BatchUpdate.tsx (1 hunks)
  • src/FieldContext.ts (1 hunks)
  • src/Form.tsx (5 hunks)
  • src/interface.ts (2 hunks)
  • src/useForm.ts (5 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/interface.ts (1)
src/BatchUpdate.tsx (1)
  • BatchTask (3-3)
src/Form.tsx (1)
src/BatchUpdate.tsx (2)
  • BatchUpdateRef (5-7)
  • BatchTask (3-3)
src/useForm.ts (2)
src/interface.ts (1)
  • InternalNamePath (6-6)
src/BatchUpdate.tsx (1)
  • BatchTask (3-3)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: WIP
🔇 Additional comments (14)
docs/demo/debug.md (1)

1-4: 文档结构合理

简洁的文档格式,正确引用了调试示例代码。

src/interface.ts (2)

4-4: 类型导入正确

正确导入了BatchTask类型,支持新的批处理机制。


237-237: 接口扩展合理

setBatchUpdate方法的添加与现有的InternalHooks接口风格一致,类型签名正确。

src/FieldContext.ts (1)

45-45: 上下文更新正确

setBatchUpdate方法的添加保持了与其他方法一致的模式,使用warningFunc作为占位符是正确的做法。

docs/examples/debug.tsx (3)

4-7: 监听组件实现简洁

WatchCom组件正确使用Form.useWatch监听字段变化,实现简洁有效。


13-20: 数据生成优化得当

使用React.useMemo正确缓存大量数据生成,避免不必要的重复计算。500个字段的数量足以展现性能问题。


35-47: 性能测试场景有效

条件渲染大量表单字段的切换场景能够有效重现性能延迟问题,为批处理优化提供了良好的测试用例。

src/Form.tsx (4)

17-17: 导入语句正确添加了批量更新相关类型。

新增的导入语句正确引入了 BatchUpdate 组件及其相关类型定义,为后续的批量更新机制提供了必要的类型支持。


74-75: 正确获取了批量更新设置钩子。

从内部钩子中解构出 setBatchUpdate 方法,这与 useForm.ts 中新增的钩子方法保持一致。


199-199: BatchUpdate 组件正确集成到渲染树中。

BatchUpdate 组件添加到 ListContext.Provider 内部是正确的,确保了批量更新组件能够正确接收到 ref 回调。


123-157: 批量更新逻辑实现需要添加错误处理。

批量更新的整体设计思路正确,通过 BatchUpdate 子组件避免 Form 自身重新渲染。但是存在一个潜在的运行时错误风险:

在第156行调用 setBatchUpdate(batchUpdate) 时,batchUpdate 函数内部会立即调用 tryFlushBatch(),但此时 batchUpdateRef.current 可能还未设置,导致任务无法正确批量执行。

建议添加错误处理和空值检查:

 const batchUpdate: BatchTask = (key, callback) => {
   batchUpdateTasksRef.current.push([key, callback]);
   tryFlushBatch();
 };

可以优化为:

 const batchUpdate: BatchTask = (key, callback) => {
   batchUpdateTasksRef.current.push([key, callback]);
+  // 延迟到下一个 tick 执行,确保 ref 已设置
+  React.startTransition(() => {
     tryFlushBatch();
+  });
 };

Likely an incorrect or invalid review comment.

src/useForm.ts (3)

41-41: 正确导入了批量任务类型。

导入 BatchTask 类型为批量更新机制提供了必要的类型支持。


123-123: 内部钩子正确暴露了批量更新设置方法。

getInternalHooks 方法中添加 setBatchUpdate 钩子,与 Form.tsx 中的使用保持一致。


219-226: 批量通知逻辑实现正确且高效。

batchNotifyWatch 方法的实现很好地解决了频繁通知的性能问题:

  • 使用数组累积需要通知的 namePath
  • 通过批量机制在合适的时机统一执行通知
  • 执行后清空累积列表,避免重复通知

这种设计符合 PR 目标中提到的性能优化需求。

Comment on lines +229 to +238
private batchUpdate: BatchTask;

private setBatchUpdate = (batchUpdate: BatchTask) => {
this.batchUpdate = batchUpdate;
};

// Batch call the task, only last will be called
private batch = (key: string, callback: VoidFunction) => {
this.batchUpdate(key, callback);
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

批量更新实现需要添加空值检查。

batch 方法直接调用 this.batchUpdate(key, callback),但 batchUpdate 在初始化时可能为 undefined,这会导致运行时错误。

建议添加空值检查:

 // Batch call the task, only last will be called
 private batch = (key: string, callback: VoidFunction) => {
+  if (!this.batchUpdate) {
+    // 如果批量更新函数尚未设置,直接执行回调
+    callback();
+    return;
+  }
   this.batchUpdate(key, callback);
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private batchUpdate: BatchTask;
private setBatchUpdate = (batchUpdate: BatchTask) => {
this.batchUpdate = batchUpdate;
};
// Batch call the task, only last will be called
private batch = (key: string, callback: VoidFunction) => {
this.batchUpdate(key, callback);
};
private batchUpdate: BatchTask;
private setBatchUpdate = (batchUpdate: BatchTask) => {
this.batchUpdate = batchUpdate;
};
// Batch call the task, only last will be called
private batch = (key: string, callback: VoidFunction) => {
if (!this.batchUpdate) {
// 如果批量更新函数尚未设置,直接执行回调
callback();
return;
}
this.batchUpdate(key, callback);
};
🤖 Prompt for AI Agents
In src/useForm.ts around lines 229 to 238, the batch method calls
this.batchUpdate without checking if it is defined, which can cause runtime
errors if batchUpdate is undefined. Add a null or undefined check before calling
this.batchUpdate in the batch method to ensure it is a valid function before
invocation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants